package cn.tedu.mall.order.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.JsonPage;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.mapper.OmsCartMapper;
import cn.tedu.mall.order.mapper.OmsOrderItemMapper;
import cn.tedu.mall.order.mapper.OmsOrderMapper;
import cn.tedu.mall.order.service.IOmsCartService;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.order.utils.IdGeneratorUtils;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderListTimeDTO;
import cn.tedu.mall.pojo.order.dto.OrderStateUpdateDTO;
import cn.tedu.mall.pojo.order.model.OmsCart;
import cn.tedu.mall.pojo.order.model.OmsOrder;
import cn.tedu.mall.pojo.order.model.OmsOrderItem;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.order.vo.OrderDetailVO;
import cn.tedu.mall.pojo.order.vo.OrderListVO;
import cn.tedu.mall.product.service.order.IForOrderSkuService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@DubboService //将来秒杀模块要调用
@Service
@Slf4j
public class OmsOrderServiceImpl implements IOmsOrderService {
    //需要调用product模块的减少sku库存的方法
    @DubboReference
    private IForOrderSkuService dubboOrderSkuService;
    //删除购物车中的商品
    @Autowired
    private IOmsCartService omsCartService;
    //新增订单
    @Autowired
    private OmsOrderMapper omsOrderMapper;
    //新增订单项
    @Autowired
    private OmsOrderItemMapper omsOrderItemMapper;

    //新增订单
    @Override
    public OrderAddVO addOrder(OrderAddDTO orderAddDTO) {
        //第一部分：收集订单的信息、准备数据
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderAddDTO,omsOrder);
        //将订单的收集和计算，单独写成一个方法
        loadOrder(omsOrder);
        //收集订单项信息
        List<OrderItemAddDTO> orderItems = orderAddDTO.getOrderItems();
        //判断订单项是否为空，为空抛出异常
        if(orderItems==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单中必须包含订单项");
        //准备一个OmsOrderItem集合
        List<OmsOrderItem> omsOrderItems = new ArrayList<>();
        //遍历订单项集合
        for (OrderItemAddDTO orderItemAddDTO : orderItems) {
            //我们需要将orderItemAddDTO转成OmsOrderItem
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            BeanUtils.copyProperties(orderItemAddDTO,omsOrderItem);
            //对omsOrderItem对象进行属性的非空判断
            loadOrderItem(omsOrderItem);
            //将omsOrder对象中的订单id赋值给omsOrderItem
            omsOrderItem.setOrderId(omsOrder.getId());
            //将omsOrderItem放入到OmsOrderItem的集合中
            omsOrderItems.add(omsOrderItem);
            //到此为止所有的订单信息收集完毕，接下来要进行数据库相关的操作
            //减少库存数
            Long skuId = omsOrderItem.getSkuId();
            int rows = dubboOrderSkuService.reduceStockNum(skuId, omsOrderItem.getQuantity());
            //如果rows影响的行数为0，就没有减少库存失败
            if(rows==0){
                log.info("商品编号为{}，库存不足",skuId);
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"库存不足");
            }
            //删除购物车中的商品
            OmsCart omsCart = new OmsCart();
            omsCart.setUserId(omsOrder.getUserId());
            omsCart.setSkuId(skuId);
            omsCartService.removeUserCarts(omsCart);
        }
        //新增订单
        omsOrderMapper.insertOrder(omsOrder);
        //新增订单项
        omsOrderItemMapper.insertOrderItem(omsOrderItems);
        //准备返回对象
        OrderAddVO orderAddVO = new OrderAddVO();
        orderAddVO.setId(omsOrder.getId()); //订单id
        orderAddVO.setSn(omsOrder.getSn()); //订单编号
        orderAddVO.setCreateTime(omsOrder.getGmtCreate()); //订单创建时间
        orderAddVO.setPayAmount(omsOrder.getAmountOfActualPay()); //实际支付金额
        //别忘记返回
        return orderAddVO;
    }

    private void loadOrderItem(OmsOrderItem omsOrderItem) {
        //判断订单项的id是否为null
        if (omsOrderItem.getId()==null){
            Long id = IdGeneratorUtils.getDistributeId("order_item");
            omsOrderItem.setId(id);
        }
        //判断skuId是否为null
        if(omsOrderItem.getSkuId()==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单商品中必须包含skuId");
    }

    //需要判断订单不能为空的属性，和价格计算
    private void loadOrder(OmsOrder omsOrder) {
        //判断用户id是否为空
        if(omsOrder.getUserId()==null){
            Long userId = getUserId();
            omsOrder.setUserId(userId);
        }
        //判断订单编号sn是否为空
        if(omsOrder.getSn()==null){
            //生成订单编号
            String sn = UUID.randomUUID().toString();
            omsOrder.setSn(sn);
        }
        //判断订单id是否为空
        if(omsOrder.getId()==null){
            //使用Leaf生成分布式ID
            Long orderId = IdGeneratorUtils.getDistributeId("order");
            omsOrder.setId(orderId);
        }
        //判断订单状态是否为空
        if(omsOrder.getState()==null){
            //默认的状态是0，表示生成订单待支付的状态
            omsOrder.setState(0);
        }
        //判断订单生成时间或者创建时间或者修改时间是否空
        //只要有一个为空，就设置成一样的时间即可
        if(omsOrder.getGmtOrder()==null || omsOrder.getGmtCreate()==null || omsOrder.getGmtModified()==null){
            LocalDateTime nowTime = LocalDateTime.now();
            omsOrder.setGmtOrder(nowTime);
            omsOrder.setGmtCreate(nowTime);
            omsOrder.setGmtModified(nowTime);
        }
        //判断商品原价是否为空，直接抛出异常
        if(omsOrder.getAmountOfOriginalPrice()==null){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单商品价格必须要有原价");
        }
        //判断运费和优惠价格是否为空，设置为0
        if(omsOrder.getAmountOfFreight()==null){
            omsOrder.setAmountOfFreight(new BigDecimal(0.0));
        }
        if(omsOrder.getAmountOfDiscount()==null){
            omsOrder.setAmountOfDiscount(new BigDecimal(0.0));
        }
        //计算实际支付金额=商品原价+运费-优惠
        BigDecimal amountOfOriginalPrice = omsOrder.getAmountOfOriginalPrice(); //商品原价
        BigDecimal amountOfFreight = omsOrder.getAmountOfFreight(); //运费
        BigDecimal amountOfDiscount = omsOrder.getAmountOfDiscount(); //优惠金额
        //实际支付金额
        BigDecimal actualPrice = amountOfOriginalPrice.add(amountOfFreight).subtract(amountOfDiscount);
        //将实际支付金额赋值给omsOrder
        omsOrder.setAmountOfActualPay(actualPrice);
    }

    @Override
    public void updateOrderState(OrderStateUpdateDTO orderStateUpdateDTO) {
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderStateUpdateDTO,omsOrder);
        omsOrderMapper.updateOrderById(omsOrder);
    }

    //分页查询订单
    @Override
    public JsonPage<OrderListVO> listOrdersBetweenTimes(OrderListTimeDTO orderListTimeDTO) {
        //默认查询最近一个月的订单信息，
        // orderListTimeDTO中的startTime和endTime是否为空，只要有一个为空就默认查询最近一个月的信息
        // 如果startTime和endTime不为空，也需要去判断时间是否合理
        validaTimeAndLoadTime(orderListTimeDTO);
        //获取userId
        Long userId = getUserId();
        orderListTimeDTO.setUserId(userId);
        //设置分页条件
        PageHelper.startPage(orderListTimeDTO.getPage(),orderListTimeDTO.getPageSize());
        //执行查询
        List<OrderListVO> orderListVOS = omsOrderMapper.selectOrdersByTimes(orderListTimeDTO);
        return JsonPage.restPage(new PageInfo<>(orderListVOS));
    }

    private void validaTimeAndLoadTime(OrderListTimeDTO orderListTimeDTO) {
        //取出时间
        LocalDateTime startTime = orderListTimeDTO.getStartTime();
        LocalDateTime endTime = orderListTimeDTO.getEndTime();
        //起始时间和结束时间判断是否为空
        if(startTime==null || endTime==null){
            //startTime就是当前时间减去一个月的时间
            startTime = LocalDateTime.now().minusMonths(1);
            //结束时间就是当前时间
            endTime = LocalDateTime.now();
            orderListTimeDTO.setStartTime(startTime);
            orderListTimeDTO.setEndTime(endTime);
        }else{
            //检查时间是否合理，不合理就是结束时间小于开始时间
            if(endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli() <
            startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
                //结束时间小于起始时间，不合理的，抛出异常
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"结束时间需要大于开始时间");
        }
    }

    @Override
    public OrderDetailVO getOrderDetail(Long id) {
        return null;
    }

    //业务逻辑层总是需要获取用户信息的，所以单独写一个方法来获取用户信息
    //通过Security的上下文对象来获取
    public CsmallAuthenticationInfo getUserInfo(){
        //获取Security上下文对象，通过上下文对象获取token
        UsernamePasswordAuthenticationToken token =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext()
                        .getAuthentication();
        //判断token是否为空
        if(token==null)
            throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"没有登录信息");
        //从token中获取用户信息
        CsmallAuthenticationInfo userInfo =
                (CsmallAuthenticationInfo) token.getCredentials();
        //返回用户信息
        return userInfo;
    }
    //获取userId的方法也是很常见的
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
